package com.choosefine.paycenter.pay.api.handler;

import com.alibaba.fastjson.JSON;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.SendResult;
import com.aliyun.openservices.ons.api.transaction.TransactionProducer;
import com.choosefine.paycenter.common.utils.ByteArrayStringUtils;
import com.choosefine.paycenter.common.utils.SerialNumberUtils;
import com.choosefine.paycenter.pay.constants.PayConstants;
import com.choosefine.paycenter.pay.dto.PayBizzRequestDto;
import com.choosefine.paycenter.pay.dto.PayOrderMessageDto;
import com.choosefine.paycenter.pay.mq.PayLocalTransactionExecuter;
import com.choosefine.paycenter.pay.service.PayVerifyService;
import com.choosefine.paycenter.pay.service.PaymentService;
import com.choosefine.paycenter.pay.utils.PayUtils;
import com.choosefine.paycenter.pay.vo.PayResultVo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Comments：支付处理器抽象类(一套处理规范：针对所有付款方式的抽象)
 * 这里定义一套支付请求的处理规范
 * Author：Jay Chang
 * Create Date：2017/3/8
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
@Getter
@Setter
@Slf4j
@Component
public abstract class AbstractPayHandler implements PayHandler{

    @Autowired
    private PayVerifyService payVerifyService;
    @Autowired
    private PaymentService paymentService;
    /**消息生产者*/
    @Autowired
    private TransactionProducer producer;
    /**（LocalTransactionExecuter是本地事务执行处理器，这里使用事务消息，即本地事务执行成功后才会投递消息给消费者）*/
    @Autowired
    private PayLocalTransactionExecuter payLocalTransactionExecuter;

    @Value("${aliyun.ons.topic.topicPay}")
    private String topicPaycenterPay;

    @Autowired
    private SerialNumberUtils serialNumberUtils;

    /**
     * 处理支付请求
     * @param payBizzRequestDto
     */
    public PayResultVo doProcess(PayBizzRequestDto payBizzRequestDto) throws Exception {
        //校验交易主体账号是否存在,是否冻结(公共的前置检查)
        payVerifyService.checkMainAccountExistAndIsBlocked(payBizzRequestDto.getAccountId());
        //校验交易对方是否存在
        payVerifyService.checkOppositeAccountsByOppo(payBizzRequestDto.getOrders());
        //校验业务流水号对应的支付单是否已经支付完成
        payVerifyService.checkHasAlreadyPaid(payBizzRequestDto.getPaySn(),payBizzRequestDto.getBizzSys(),payBizzRequestDto.getBizzSn());
        //针对不同的付款方式，有不同的处理
        return doProcessSpecific(payBizzRequestDto);
    }

    /**
     * 不同付款方式，有不同的处理，留给具体支付处理器来实现
     * @param payBizzRequestDto
     */
    protected abstract PayResultVo doProcessSpecific(PayBizzRequestDto payBizzRequestDto) throws Exception;

    /**
     * 发送支付成功的消息
     * @param payBizzRequestDto
     */
    protected void sendPaidSuccessMessage(final PayBizzRequestDto payBizzRequestDto){
        PayOrderMessageDto payOrderMessageDto = PayUtils.getInstance().getPayOrderMessageDto(payBizzRequestDto);
        payOrderMessageDto.setSuccess(true);
        //如果是从账单发起的
        if(serialNumberUtils.isPayBizzSn(payBizzRequestDto.getBizzSn())) {
            payOrderMessageDto.setBizzSn(null);
        }
        byte[]  msgBody = ByteArrayStringUtils.getInstance().string2ByteArray(JSON.toJSONString(payOrderMessageDto),"UTF-8");
        Message message = new Message(topicPaycenterPay,PayConstants.PAY_TAG_PAY_SUCCESS,payBizzRequestDto.getPaySn(),msgBody);
        //发送事务消息
        SendResult sendResult = producer.send(message,payLocalTransactionExecuter,payBizzRequestDto.getPaySn());
        log.info(sendResult.toString());
    }

    /**
     * 发送支付失败的消息
     * @param payBizzRequestDto
     */
    protected void sendPaidFailureMessage(final PayBizzRequestDto payBizzRequestDto){
        PayOrderMessageDto payOrderMessageDto = PayUtils.getInstance().getPayOrderMessageDto(payBizzRequestDto);
        payOrderMessageDto.setSuccess(false);
        //如果是从账单发起的
        if(serialNumberUtils.isPayBizzSn(payBizzRequestDto.getBizzSn())) {
            payOrderMessageDto.setBizzSn(null);
        }
        byte[]  msgBody = ByteArrayStringUtils.getInstance().string2ByteArray(JSON.toJSONString(payOrderMessageDto),"UTF-8");
        Message message = new Message(topicPaycenterPay,PayConstants.PAY_TAG_PAY_FAILURE,payBizzRequestDto.getPaySn(),msgBody);
        //发送事务消息
        SendResult sendResult = producer.send(message,payLocalTransactionExecuter,payBizzRequestDto.getPaySn());
        log.info(sendResult.toString());
    }
}
